using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using Microsoft.SqlServer.Dts.Runtime;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using System.Collections;


namespace Microsoft.SharedSource.SqlServer.MDDE.Components
{
    [System.Diagnostics.CodeAnalysis.
        SuppressMessage("Microsoft.Naming", "CA1705:LongAcronymsShouldBePascalCased")]
    public sealed class MDDEExecutionDAG : MDDEComponent, IEnumerator, IEnumerable
    {
        private PrecedenceConstraints precedenceConstraints;
        private IDTSPathCollection100 pathCollection;
        private MDDEComponent parentComponent;

        #region Constructors

        /// <summary>
        /// Creates a Execution DAG for a Packge.
        /// </summary>
        /// <param name="package">Package, for which Execution DAG is to be created</param>
        public MDDEExecutionDAG(Package package)
            : base(package, package, package.Name, "Package")
        {
            if (null == package)
                throw new ArgumentNullException();

            this.parentComponent = this;
            this.precedenceConstraints = package.PrecedenceConstraints;

            #region Populate Variables
            this.AddSucceessorVariables(this, this.Uri);
            #endregion

            #region Populate Connection Manager
            foreach (ConnectionManager connectionManager in package.Connections)
            {
                MDDEComponent component = MDDEComponentFactory.CreateInstance(this.package,
                    connectionManager.GetType().ToString(), connectionManager,
                    connectionManager.Name, this.Uri + "/Connection=" + connectionManager.Name);
                this.successors.Add(component);
                component.Predecessors.Add(this);
            }
            #endregion

            #region Populate Executables
            foreach (Executable executable in package.Executables)
            {
                bool isExecutableConstrainted = false;
                foreach (PrecedenceConstraint pc in package.PrecedenceConstraints)
                {
                    if (pc.ConstrainedExecutable.Equals(executable))
                    {
                        isExecutableConstrainted = true;
                        break;
                    }
                }
                if (!isExecutableConstrainted)
                {
                    string uri = this.Uri + "/Executable=" + (executable as DtsContainer).Name;
                    MDDEComponent component = MDDEComponentFactory.CreateInstance(this.package,
                            (executable as DtsContainer).CreationName, executable, 
                            (executable as DtsContainer).Name, uri);
                    this.Successors.Add(component);
                    component.Predecessors.Add(this);
                    this.AddSucceessorComponents(component, this.Uri);
                }
            }
            #endregion

            #region Populate Event Handlers
            //TODO
            #endregion

            #region Populate Log Providers
            //TODO
            #endregion
        }

        /// <summary>
        /// Creates a Execution DAG for a component.
        /// </summary>
        /// <param name="package">Package, of which component is a part</param>
        /// <param name="parentComponent">Parent MDDEComponent, this DAG is a innerExectableDag to 
        /// that component</param>
        /// <param name="component">Component, for which innerExecutableDag needs to be created.
        /// </param>
        /// <param name="rootURI">URI of component</param>
        public MDDEExecutionDAG(Package package, MDDEComponent parentComponent, 
            DtsContainer component, string rootURI)
            : base(package, component, component.Name, rootURI)
        {
            if (null == package || null == parentComponent || null == component 
                || null == rootURI || rootURI == string.Empty)
                throw new ArgumentNullException();

            this.parentComponent = parentComponent;
            //Check the type of component and call the initialize function accordingly.
            if (component is TaskHost)
            {
                if ((component as TaskHost).InnerObject is MainPipe)
                    this.InitializeDagForDataFlowTask((component as TaskHost), rootURI);
                else
                    this.InitializeDagForTask((component as TaskHost), rootURI);
            }
            else //Else it is a container
                this.InitializeDagForContainer(component, rootURI);

        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Generates the changes Xml of complete dag against subject.
        /// </summary>
        /// <param name="subject">Another Executaion DAG against which changes XML need to be 
        /// generated.</param>
        /// <param name="changeXml">XML document, in which changeXML is returned</param>
        public override void GetChangeXml(MDDEComponent subject, XmlDocument changeXml)
        {
            if ((null == subject) || (null == changeXml))
                throw new ArgumentNullException();

            if (!(subject is MDDEExecutionDAG))
                throw new ArgumentException();

            foreach (MDDEComponent component in this)
            {
                MDDEComponent subjectComponent = (subject as MDDEExecutionDAG).
                    GetMDDEComponentByName(component.Name, component.GetType());
                if (null != subjectComponent)
                    component.GetChangeXml(subjectComponent, changeXml);
                //If component is not found in subject DAG then ignore that.
            }
        }

        /// <summary>
        /// Generates the changes Xml of complete dag against subject.
        /// </summary>
        /// <param name="subject">Another Executaion DAG against which changes XML need to be 
        /// generated.</param>
        public XmlDocument GetChangeXml(MDDEComponent subject)
        {
            if (null == subject)
                throw new ArgumentNullException();

            if (!(subject is MDDEExecutionDAG))
                throw new ArgumentException();

            XmlDocument changeXml = new XmlDocument();
            XmlElement element = changeXml.CreateElement("PackageChanges");
            changeXml.AppendChild(element);

            List<string> visitedComponent = new List<string>();

            this.GetChangeXml(subject, changeXml);

            return changeXml;
        }

        /// <summary>
        /// Applies the changes on all the components of the DAG. and Validates the package 
        /// afterwords.
        /// </summary>
        /// <param name="changeXml">Changes to be applied on the package</param>
        public bool ApplyChanges(XmlDocument changeXml)
        {
            if (!(this.innerComponent is Package))
                throw new Exception("This function should be called on package level DAG only.");

            Package originalPackage = new Package();
            string packageBody;
            this.package.SaveToXML(out packageBody, null);
            originalPackage.LoadFromXML(packageBody, null);

            MDDEExecutionDAG originalPackageDag = new MDDEExecutionDAG(originalPackage);

            return this.ApplyChanges(changeXml, originalPackageDag);
        }

        /// <summary>
        /// Applies the changes on all the components of the DAG. and Validates the package 
        /// afterwords.
        /// </summary>
        /// <param name="changeXml">Changes to be applied on the package</param>
        /// <param name="packageName">New name of the package, after appling the changes</param>
        public bool ApplyChanges(XmlDocument changeXml, string packageName)
        {
            try
            {
                if (this.ApplyChanges(changeXml))
                {
                    if (this.InnerComponent is Package)
                        (this.innerComponent as Package).Name = packageName;
                    return true;
                }
                return false;
            }

            catch
            {
                // TODO: Add to Log
                return false;
            }
        }

        /// <summary>
        /// Applies the changes on all the components of the DAG. and Validates the package 
        /// afterwords.
        /// </summary>
        /// <param name="changeXml">Changes to be applied on the package</param>
        /// <param name="originalPackage">Original copy of the package</param>
        public override bool ApplyChanges(XmlDocument changeXml, MDDEExecutionDAG originalPackage)
        {
            if (null == changeXml || null == originalPackage)
                throw new ArgumentNullException();

            foreach (MDDEComponent component in this)
            {
                component.ApplyChanges(changeXml, originalPackage);
            }

            return this.Validate();
        }

        /// <summary>
        /// Structural comparision of DAG.
        /// </summary>
        /// <param name="subject">DAG, against which comparision to be done</param>
        /// <param name="deepCompare">Flag, specifinge wether inner dag needs to be compared or 
        /// not.</param>
        public override bool CompareTo(MDDEComponent subject, bool deepCompare)
        {
            if (!(subject is MDDEExecutionDAG))
                return false;

            List<string> visitedComponent = new List<string>();
            return this.Compare(this.Successors, subject.Successors, visitedComponent);
        }

        /// <summary>
        /// Reports the structural difference between two DAG in terms of addition and deletion 
        /// of components.
        /// </summary>
        /// <param name="subject">DAG, against which comparision to be done</param>
        /// <param name="differenceReport">XMLDocument in which difference is returned</param>
        public override void GetDifference(MDDEComponent subject, XmlDocument differenceReport)
        {
            if (null == differenceReport)
                throw new ArgumentNullException();

            if (null == subject)
            {
                XmlNode deletedNode = 
                    differenceReport.SelectSingleNode("/PackageDifference/DeletedComponent");
                //All the components are deleted components
                foreach (MDDEComponent component in this)
                {
                    deletedNode.AppendChild(
                        this.CreateComponentElement(component, differenceReport));
                    component.GetDifference(subject, differenceReport);
                }
            }
            else
            {
                if (!(subject is MDDEExecutionDAG))
                    throw new ArgumentException();

                XmlNode deletedNode = 
                    differenceReport.SelectSingleNode("/PackageDifference/DeletedComponent");
                XmlNode addedNode = 
                    differenceReport.SelectSingleNode("/PackageDifference/AddedComponent");
                //Get deleted component 
                foreach (MDDEComponent component in this)
                {
                    MDDEComponent subjectComponent = (subject as MDDEExecutionDAG).
                        GetMDDEComponentByName(component.Name, component.GetType());
                    if (null == subjectComponent || !component.CompareTo(subjectComponent, false))
                    {
                        deletedNode.AppendChild(
                            this.CreateComponentElement(component, differenceReport));
                        component.GetDifference(null, differenceReport);
                    }
                    else
                    {
                        component.GetDifference(subjectComponent, differenceReport);
                    }
                }

                //Get newly added component by passing subject as object and object as subject.
                foreach (MDDEComponent subjectComponent in (subject as MDDEExecutionDAG))
                {
                    MDDEComponent component = this.
                        GetMDDEComponentByName(subjectComponent.Name, subjectComponent.GetType());
                    if (null == component || !component.CompareTo(subjectComponent, false))
                    {
                        addedNode.AppendChild(
                            this.CreateComponentElement(subjectComponent, differenceReport));

                        //All the node in innerExecutionDAG of that component should go into 
                        //Added component list
                        XmlDocument childDifferenceReport = this.CreateDifferenceReport();
                        subjectComponent.GetDifference(null, childDifferenceReport);

                        XmlNode deletedChildNode = childDifferenceReport.
                            SelectSingleNode("/PackageDifference/DeletedComponent");

                        foreach (XmlNode node in deletedChildNode.ChildNodes)
                        {
                            if (node is XmlElement)
                            {
                                addedNode.AppendChild(differenceReport.ImportNode(node, true));
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Reports the structural difference between two DAG in terms of addition and deletion 
        /// of components.
        /// </summary>
        /// <param name="subject">DAG, against which comparision to be done</param>
        public XmlDocument GetDifference(MDDEComponent subject)
        {
            if (null == subject)
                throw new ArgumentNullException();

            if (!(subject is MDDEExecutionDAG))
                throw new ArgumentException();

            XmlDocument differenceReport = this.CreateDifferenceReport();

            this.GetDifference(subject, differenceReport);

            return differenceReport;
        }

        /// <summary>
        /// Returns the MDDEComponent for the given URI, null if component not found.
        /// </summary>
        /// <param name="uri">URI, for which component is needs to be searched.</param>
        public MDDEComponent GetMDDEComponentByUri(string uri)
        {
            if (uri == this.Uri)
                return parentComponent;
            if (uri.StartsWith(this.Uri))
            {
                string subUri = uri.Replace(this.Uri + "/", string.Empty);
                if (subUri.Contains("/"))
                {
                    string componentName = subUri.Substring(
                        subUri.IndexOf('=') + 1, subUri.IndexOf('/') - subUri.IndexOf('=') - 1);
                    return this.GetMDDEComponentByName(
                        componentName, typeof(MDDEContainer)).GetChildComponent(uri);
                }
                else
                {
                    string componentName = subUri.Substring(subUri.IndexOf('=') + 1);
                    string componentType = subUri.Substring(0, subUri.IndexOf('='));
                    Type type;
                    switch (componentType)
                    {
                        case "Executable":
                            type = typeof(MDDEContainer);
                            break;
                        case "Variable":
                            type = typeof(MDDEVariable);
                            break;
                        case "ConnectionManager":
                            type = typeof(MDDEConnectionManager);
                            break;
                        case "Component":
                            type = typeof(MDDEDataFlowComponent);
                            break;
                        default:
                            type = typeof(MDDEComponent);
                            break;
                    }
                    return this.GetMDDEComponentByName(componentName, type);
                }
            }
            return null;
        }

        /// <summary>
        /// Returns the MDDEComponent for the given Name, null if component not found.
        /// </summary>
        /// <param name="name">Name, for which component is needs to be searched.</param>
        /// <param name="type">Type of component to be searched.</param>
        public MDDEComponent GetMDDEComponentByName(string name, Type type)
        {
            return this.GetMDDEComponentByName(this.successors, name, type);
        }

        /// <summary>
        /// Returns the package's tree view in xml format.
        /// </summary>
        public override XmlDocument GetComponentTree()
        {
            // This class can host either a package, container or a data flow component.
            // Cater for a package level DAG here.
            if (innerComponent is Package)
                return GetPackageTree();
            else
                return null;
        }

        /// <summary>
        /// Validates the package and all its component.
        /// </summary>
        public override bool Validate()
        {
            try
            {
                if (innerComponent is Package)
                {
                    Package package = (this.innerComponent as Package);
                    DTSExecResult result =
                        package.Validate(package.Connections, package.Variables, null, null);

                    if (result != DTSExecResult.Success)
                        return false;
                }

                foreach (MDDEComponent component in this)
                {
                    if (!component.Validate())
                        return false;
                }

                return true;
            }

            catch
            {
                // TODO: Add to Log
                return false;
            }
        }

        #endregion

        #region Private Methods
        /// <summary>
        /// Compares all the component in first list against the component in second list.
        /// </summary>
        /// <param name="successors">First list of component</param>
        /// <param name="targetSuccessors">Second list of component.</param>
        /// <param name="visitedComponent">List which keeps track of already visited (compared) 
        /// components.</param>
        private bool Compare(List<MDDEComponent> successors, List<MDDEComponent> targetSuccessors, 
            List<string> visitedComponent)
        {
            if (successors.Count != targetSuccessors.Count)
                return false;

            foreach (MDDEComponent component in successors)
            {
                if (visitedComponent.Contains(component.Uri))
                    continue;

                visitedComponent.Add(component.Uri);

                bool branchFound = false;

                foreach (MDDEComponent targetComponent in targetSuccessors)
                {
                    if (component.CompareTo(targetComponent, true))
                    {
                        if (this.Compare(
                            component.Successors, targetComponent.Successors, visitedComponent))
                        {
                            branchFound = true;
                            break;
                        }
                    }
                }
                if (!branchFound)
                    return false;
            }
            return true;
        }

        /// <summary>
        /// Find all the successor components of the "component" and add them to Successors list 
        /// of the "component".
        /// </summary>
        /// <param name="component">component, for which successors need to searched.</param>
        /// <param name="rootURI">URI of "component".</param>
        private void AddSucceessorComponents(MDDEComponent component, string rootURI)
        {
            foreach (PrecedenceConstraint precedenceConstraint in this.precedenceConstraints)
            {
                if (precedenceConstraint.PrecedenceExecutable.Equals(component.InnerComponent))
                {
                    string uri = rootURI + "/Executable=" + 
                        (precedenceConstraint.ConstrainedExecutable as DtsContainer).Name;
                    MDDEComponent successorComponent = this.GetMDDEComponentByUri(uri);
                    if (null == successorComponent)
                    {
                        successorComponent = MDDEComponentFactory.CreateInstance(this.package,
                            (precedenceConstraint.ConstrainedExecutable as DtsContainer).CreationName,
                            precedenceConstraint.ConstrainedExecutable,
                            (precedenceConstraint.ConstrainedExecutable as DtsContainer).Name, uri);
                        component.Successors.Add(successorComponent);
                        successorComponent.Predecessors.Add(component);

                        this.AddSucceessorComponents(successorComponent, rootURI);
                    }
                    else
                    {
                        component.Successors.Add(successorComponent);
                        successorComponent.Predecessors.Add(component);
                    }
                }
            }
        }

        /// <summary>
        /// Find all the successor variables of the "component" and add them to Successors list 
        /// of the "component".
        /// </summary>
        /// <param name="component">component, for which successors need to searched.</param>
        /// <param name="rootURI">URI of "component".</param>
        private void AddSucceessorVariables(MDDEComponent component, string rootURI)
        {
            DtsContainer containerComponent = component.InnerComponent as DtsContainer;
            foreach (Variable variable in containerComponent.Variables)
            {
                if (!variable.SystemVariable)
                {
                    //To avoid the varaibles in parent scope we need to check the defination scope of the variable
                    string[] strComponents = variable.GetPackagePath().Split(new string[1] { "\\" }, StringSplitOptions.None);
                    int index = strComponents[strComponents.Length - 1].IndexOf(".Variables[");
                    string scope = strComponents[strComponents.Length - 1].Substring(0, index);

                    if (scope == containerComponent.Name || ((containerComponent is Package) && scope == "Package"))
                    {
                        MDDEComponent variableComponent = MDDEComponentFactory.CreateInstance(
                            this.package, variable.GetType().ToString(), variable, variable.Name,
                            rootURI + "/Variable=" + variable.Name);

                        component.Successors.Add(variableComponent);
                        variableComponent.Predecessors.Add(component);
                    }
                }
            }
        }

        /// <summary>
        /// Find all the successor components of the "component" and add them to Successors list 
        /// of the "component".
        /// </summary>
        /// <param name="component">component, for which successors need to searched.</param>
        /// <param name="rootURI">URI of "component".</param>
        private void AddSucceessorDataFlowComponents(MDDEComponent component, string rootURI)
        {
            IDTSComponentMetaData100 componentMetadata = component.InnerComponent as IDTSComponentMetaData100;
            foreach (IDTSPath100 componentPath in this.pathCollection)
            {
                if (componentPath.StartPoint.Component.Name.CompareTo(componentMetadata.Name) == 0)
                {
                    string uri = rootURI + "/Component=" + componentPath.EndPoint.Component.Name;
                    MDDEComponent successorComponent = this.GetMDDEComponentByUri(uri);
                    if (null == successorComponent)
                    {
                        successorComponent = MDDEComponentFactory.CreateInstance(this.package,
                            componentPath.EndPoint.Component.ComponentClassID.ToString(),
                            componentPath.EndPoint.Component, componentPath.EndPoint.Component.Name, uri);
                        component.Successors.Add(successorComponent);
                        successorComponent.Predecessors.Add(component);
                        this.AddSucceessorDataFlowComponents(successorComponent, rootURI);
                    }
                    else
                    {
                        component.Successors.Add(successorComponent);
                        successorComponent.Predecessors.Add(component);
                    }
                }
            }
        }

        /// <summary>
        /// Creates an XMLElement for component to be inserted in Differenece Report.
        /// </summary>
        /// <param name="component">component, for which XMLElement needs to be created.</param>
        /// <param name="differenceReport">XMLDocument, in whose context element needs to be 
        /// created.</param>
        private XmlElement CreateComponentElement(
            MDDEComponent component, XmlDocument differenceReport)
        {
            XmlElement componentElement = differenceReport.CreateElement("Component");

            XmlAttribute name = differenceReport.CreateAttribute("Name");
            name.Value = component.Name;

            XmlAttribute uri = differenceReport.CreateAttribute("Uri");
            uri.Value = component.Uri;

            componentElement.Attributes.Append(name);
            componentElement.Attributes.Append(uri);

            return componentElement;
        }

        /// <summary>
        /// Returns the package's tree view in xml format.
        /// </summary>
        private XmlDocument GetPackageTree()
        {
            // Create a tree document.
            XmlDocument componentTree = new XmlDocument();

            // Append the root node.
            XmlElement xRoot = AppendChildElement( componentTree, "Node",
                new string[] { "Type", "Package", "Name", package.Name,
                    "Uri", "Package=" + package.Name });

            // Add the 'Executables' node.
            XmlElement xExecutables = AppendChildElement( xRoot, "Node",
                new string[]{ "Type", "Collection", "Name", "Executables",
                    "Uri", Uri + "/Executables", "ClassId", string.Empty, 
                    "RowsetDescriptorType", string.Empty, "ContainsMappings", "False",
                    "ContainsCollections", "False" });

            // Add the 'Precedence Constraints' node.
            XmlElement xConstraints = AppendChildElement( xRoot, "Node",
                new string[]{ "Type", "Collection", "Name", "Precedence Constraints",
                    "Uri", Uri + "/Precedence Constraints", "ClassId", string.Empty,
                    "RowsetDescriptorType", string.Empty,
                    "ContainsMappings", "False", "ContainsCollections", "False" });

            // Add the 'Event Handlers' node.
            XmlElement xEventHandlers = AppendChildElement( xRoot, "Node",
                new string[]{ "Type", "Collection", "Name", "Event Handlers",
                    "Uri", Uri + "/Event Handlers", "ClassId", string.Empty,
                    "RowsetDescriptorType", string.Empty, "ContainsMappings", "False",
                    "ContainsCollections", "False" });

            // Add the 'Log Providers' node.
            XmlElement xLogProviders = AppendChildElement( xRoot, "Node",
               new string[]{ "Type", "Collection", "Name", "Log Providers",
                    "Uri", Uri + "/Log Providers", "ClassId", string.Empty,
                    "RowsetDescriptorType", string.Empty,
                    "ContainsMappings", "False", "ContainsCollections", "False" });

            // Add the 'Connection Managers' node.
            XmlElement xConnectionManagers = AppendChildElement( xRoot, "Node",
                new string[]{ "Type", "Collection", "Name", "Connection Managers",
                    "Uri", Uri + "/Connection Managers", "ClassId", string.Empty,
                    "RowsetDescriptorType", string.Empty,
                    "ContainsMappings", "False", "ContainsCollections", "False" });

            // Add the 'Variables' node.
            XmlElement xVariables = AppendChildElement( xRoot, "Node",
                new string[]{ "Type", "Collection", "Name", "Variables",
                    "Uri", Uri + "/Variables", "ClassId", string.Empty,
                    "RowsetDescriptorType", string.Empty,
                    "ContainsMappings", "False", "ContainsCollections", "False" });

            // Traverse the execution DAG in execution order.
            foreach (MDDEComponent graphNode in this)
            {
                // Get the component tree of node.
                XmlDocument xSuccessorTree = graphNode.GetComponentTree();

                if (xSuccessorTree == null)
                    continue;

                // Append the successor tree to appropriate parent node.

                // Check for executables.
                if (graphNode is MDDEContainer)
                    // Append the child tree to 'Executables' node.
                    xExecutables.AppendChild(
                        xRoot.OwnerDocument.ImportNode(
                        xSuccessorTree.DocumentElement, true));

                // Check for Precedence Constraints.
                if (graphNode is MDDEPrecedenceConstraint)
                    // Append the child tree to 'Precedence Constraints' node.
                    xConstraints.AppendChild(
                        xRoot.OwnerDocument.ImportNode(
                        xSuccessorTree.DocumentElement, true));

                // Check for Event Handlers.
                if (graphNode is MDDEEventHandler)
                    // Append the child tree to 'Event Handlers' node.
                    xEventHandlers.AppendChild(
                        xRoot.OwnerDocument.ImportNode(
                        xSuccessorTree.DocumentElement, true));

                // Check for Log Providers.
                if (graphNode is MDDELogProvider)
                    // Append the child tree to 'Log Providers' node.
                    xLogProviders.AppendChild(
                        xRoot.OwnerDocument.ImportNode(
                        xSuccessorTree.DocumentElement, true));

                // Check for Connection Managers.
                if (graphNode is MDDEConnectionManager)
                    // Append the child tree to 'Connection Managers' node.
                    xConnectionManagers.AppendChild(
                        xRoot.OwnerDocument.ImportNode(
                        xSuccessorTree.DocumentElement, true));

                // Check for Variables.
                if (graphNode is MDDEVariable)
                    // Append the child tree to 'Variables' node.
                    xVariables.AppendChild(
                        xRoot.OwnerDocument.ImportNode(
                        xSuccessorTree.DocumentElement, true));
            }

            return componentTree;
        }

        /// <summary>
        /// Creates a skeleton difference report.
        /// </summary>
        private XmlDocument CreateDifferenceReport()
        {
            XmlDocument differenceReport = new XmlDocument();

            XmlElement rootElement = differenceReport.CreateElement("PackageDifference");
            XmlElement addedComponentNode = differenceReport.CreateElement("AddedComponent");
            XmlElement deletedComponentNode = differenceReport.CreateElement("DeletedComponent");

            rootElement.AppendChild(addedComponentNode);
            rootElement.AppendChild(deletedComponentNode);

            differenceReport.AppendChild(rootElement);

            return differenceReport;
        }

        /// <summary>
        /// Creates DAG for Data Flow Task.
        /// </summary>
        /// <param name="component">component, for which DAG needs to be created.</param>
        /// <param name="rootURI">URI of the component.</param>
        private void InitializeDagForDataFlowTask(TaskHost component, string rootURI)
        {
            if (!(component.InnerObject is MainPipe))
                throw new ArgumentException();

            MainPipe mainPipe = component.InnerObject as MainPipe;
            this.pathCollection = mainPipe.PathCollection;

            #region Populate Variables
            this.AddSucceessorVariables(this, this.Uri);
            #endregion

            #region Populate components
            foreach (IDTSComponentMetaData100 componentMetaData in mainPipe.ComponentMetaDataCollection)
            {
                bool isComponentDependent = false;
                foreach (IDTSPath100 componentPath in mainPipe.PathCollection)
                {
                    if (componentPath.EndPoint.Component.Name.CompareTo(componentMetaData.Name) == 0)
                    {
                        isComponentDependent = true;
                        break;
                    }
                }
                if (!isComponentDependent)
                {
                    string uri = this.Uri + "/Component=" + componentMetaData.Name;
                    MDDEComponent mddeComponent = MDDEComponentFactory.CreateInstance(this.package,
                            componentMetaData.ComponentClassID.ToString(), componentMetaData, componentMetaData.Name, uri);
                    this.Successors.Add(mddeComponent);
                    mddeComponent.Predecessors.Add(this);
                    this.AddSucceessorDataFlowComponents(mddeComponent, this.Uri);
                }
            }
            #endregion
        }

        /// <summary>
        /// Creates DAG for Control Flow Task.
        /// </summary>
        /// <param name="component">component, for which DAG needs to be created.</param>
        /// <param name="rootURI">URI of the component.</param>
        private void InitializeDagForTask(TaskHost component, string rootURI)
        {
            #region Populate Variables
            this.AddSucceessorVariables(this, this.Uri);
            #endregion
        }

        /// <summary>
        /// Creates DAG for container component.
        /// </summary>
        /// <param name="component">component, for which DAG needs to be created.</param>
        /// <param name="rootURI">URI of the component.</param>
        private void InitializeDagForContainer(DtsContainer component, string rootURI)
        {
            //Using reflection here to get the property of the actual type of the component.
            this.precedenceConstraints = (PrecedenceConstraints)component.GetType().GetProperty("PrecedenceConstraints").GetValue(component, null);

            #region Populate Variables
            this.AddSucceessorVariables(this, this.Uri);
            #endregion

            #region Populate Executables
            Executables executables = (Executables)component.GetType().GetProperty("Executables").GetValue(component, null);
            foreach (Executable executable in executables)
            {
                bool isExecutableConstrainted = false;
                foreach (PrecedenceConstraint pc in this.precedenceConstraints)
                {
                    if (pc.ConstrainedExecutable.Equals(executable))
                    {
                        isExecutableConstrainted = true;
                        break;
                    }
                }
                if (!isExecutableConstrainted)
                {
                    string uri = this.Uri + "/Executable=" + (executable as DtsContainer).Name;
                    MDDEComponent mddeComponent = MDDEComponentFactory.CreateInstance(this.package,
                            (executable as DtsContainer).CreationName, executable, (executable as DtsContainer).Name, uri);
                    this.Successors.Add(mddeComponent);
                    mddeComponent.Predecessors.Add(this);
                    this.AddSucceessorComponents(mddeComponent, this.Uri);
                }
            }
            #endregion

           
        }

        /// <summary>
        /// Retruns a MDDEComponent which matchase with the given name and type in the list of 
        /// successors.
        /// </summary>
        /// <param name="successors">List of component in which required component needs to be 
        /// searched.</param>
        /// <param name="name">Name of component to be searched.</param>
        /// <param name="type">Type of component to be searched.</param>
        private MDDEComponent GetMDDEComponentByName(List<MDDEComponent> successors, string name, Type type)
        {
            foreach (MDDEComponent component in successors)
            {
                if (component.Name == name && (component.GetType() == type || component.GetType().IsSubclassOf(type)))
                    return component;
                MDDEComponent childComponent = GetMDDEComponentByName(component.Successors, name, type);
                if (null != childComponent)
                    return childComponent;
            }
            return null;
        }

        #endregion

        #region IEnumerator Implementation.
        // The implementation returns the components 
        // that make up the DAG in breadth first order.

        // A queue to maintain the components to be processed.
        Queue<MDDEComponent> componentQueue =
            new Queue<MDDEComponent>();

        // A list of processed components.
        List<MDDEComponent> processedComponents =
            new List<MDDEComponent>();

        /// <summary>
        /// Returns the currently selected node inside the DAG.
        /// </summary>
        object IEnumerator.Current
        {
            get { return componentQueue.Peek(); }
        }

        /// <summary>
        /// Selects the next node in the DAG.
        /// </summary>
        /// <returns></returns>
        bool IEnumerator.MoveNext()
        {
            // BUG1: Not thread safe.

            // If we do not have any more nodes to process, return false.
            if (componentQueue.Count == 0 && processedComponents.Count != 0)
                return false;

            // Check for the initial condition.
            if (componentQueue.Count == 0 && processedComponents.Count == 0)
            {
                // Return false, if there are no successors to this DAG node.
                if (this.Successors.Count == 0)
                    return false;

                // Fill in all the successors for this DAG.
                foreach (MDDEComponent successor in this.Successors)
                    componentQueue.Enqueue(successor);

                processedComponents.Add(this);
            }

            // Dequeue the first element as long as it is either 
            // processed or all of its parents are not processed.
            bool foundComponentToBeProcessed = false;
            while (!foundComponentToBeProcessed)
            {
                // Peek on the first element in the queue.
                MDDEComponent firstElement = componentQueue.Peek();
                bool componentDequeued = false;

                // Dequeue if its already processed.
                if (processedComponents.Contains(firstElement))
                {
                    componentQueue.Dequeue();

                    // If the queue is empty, return false.
                    if (componentQueue.Count == 0)
                        return false;

                    continue;
                }

                // Dequeue if any of the parents are not processed.
                foreach (MDDEComponent predecessor in firstElement.Predecessors)
                    if (!processedComponents.Contains(predecessor))
                    {
                        componentQueue.Dequeue();
                        componentDequeued = true;

                        // If the queue is empty, return false.
                        if (componentQueue.Count == 0)
                            return false;

                        break;
                    }

                // Process this component if it survives the earlier dequeuing cycles.
                if (!componentDequeued)
                    foundComponentToBeProcessed = true;
            }

            // Fill in the successors of first component.
            foreach (MDDEComponent successor in
                componentQueue.Peek().Successors)
                componentQueue.Enqueue(successor);

            // Add the first component to processed list.
            processedComponents.Add(componentQueue.Peek());

            // If the queue is empty, return false.
            if (componentQueue.Count == 0)
                return false;

            return true;
        }

        void IEnumerator.Reset()
        {
            // Set the enumerator to its initial position, 
            // which is before the first element in the collection.
            componentQueue.Clear();

            foreach (MDDEComponent successor in this.Successors)
                componentQueue.Enqueue(successor);

            processedComponents.Clear();

            processedComponents.Add(this);
        }

        #endregion

        #region IEnumerable Members

        IEnumerator IEnumerable.GetEnumerator()
        {
            ((IEnumerator)this).Reset();
            return (IEnumerator)this;
        }

        #endregion
    }
}
